feat(triggers): first real SKILL_OBSERVATION_TRIGGER — clipboard URL → web_fetch#14
Merged
Merged
Conversation
…→ web_fetch
Phase 2 Step 6 shipped the trigger system but no skill declared a
SKILL_OBSERVATION_TRIGGER constant, so trigger_fired/blocked audit
events stayed dormant in production. This PR ships the first real
declarative trigger to prove Step 6 end-to-end.
Skill: clipboard_url_fetch
- Trigger type: clipboard_pattern
- Pattern: r"https?://[^\s<>'\"]+"
- Cooldown: 600s (10 min) per (skill, trigger) key
- require_confirmation: True → routes through codec_ask_user.ask
- destructive: False → no strict-consent verb-match needed
- Stable key: clipboard_url_fetch:07734ae8
Runtime:
- Trigger fires on observation_tick when clipboard preview matches
- User sees ask_user prompt: "Fetch and summarize this URL?"
- On approval: skill reads pbpaste at runtime, delegates to
web_fetch.run(url), returns content truncated to 2000 chars
- On reject / timeout: codec_triggers emits trigger_blocked
Manual paths (chat / voice / MCP) work too via SKILL_TRIGGERS list:
"fetch clipboard url", "summarize clipboard", etc.
Tests: 15 new tests in tests/test_clipboard_url_fetch.py covering
metadata correctness (incl. CHAT_SKILL_ALLOWLIST regression — same
gotcha as PR #13), trigger schema validation against
codec_triggers._validate_trigger_dict, pattern semantics, URL
extraction, and 5 run() behaviors. All mock subprocess + web_fetch
— never makes a real network call, never reads the user's clipboard.
Full suite: 839 passed / 20 failed / 73 skipped — same 20/73 baseline
as main, +15 from new tests.
Verified via direct invocation of
codec_triggers.discover_triggers(SkillRegistry) → 1 trigger found
(was 0 on main).
Deploy:
git pull && cp skills/clipboard_url_fetch.py ~/.codec/skills/
pm2 restart codec-observer codec-dashboard
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
First real declarative
SKILL_OBSERVATION_TRIGGERshipped after Phase 2 Step 6. Until now,trigger_fired/trigger_blockedevents were dormant in production because zero installed skills declared the constant. This PR proves Step 6 end-to-end.What this ships
Skill:
clipboard_url_fetch— auto-fetches HTTP/HTTPS URLs copied to clipboard, with a consent prompt before any network call.typeclipboard_patternpatternr"https?://[^\s<>'\"]+"cooldown_seconds600(10 min per(skill, trigger)key)require_confirmationTrue→ routes throughcodec_ask_user.askdestructiveFalse→ no strict-consent verb-match neededclipboard_url_fetch:07734ae8Runtime flow
codec_observer.poll()capturessnapshot["clipboard"]["preview"]codec_triggers.evaluate(snapshot)matches the regex → emitstrigger_evaluated_await_confirmationpostsask_usernotification: "Fetch and summarize this URL?"_dispatch→codec_dispatch.run_skill("clipboard_url_fetch", ...)pbpasteat runtime (handles clipboard changes between trigger fire and skill execution), delegates to existingweb_fetch.run(url), returns content truncated to 2000 charstrigger_fired(paired with the earliertrigger_evaluated)Manual paths (chat / voice / MCP) work too via
SKILL_TRIGGERS = ["fetch clipboard url", "summarize clipboard", ...].Files
skills/clipboard_url_fetch.pytests/test_clipboard_url_fetch.pycodec_dashboard.pyclipboard_url_fetchtoCHAT_SKILL_ALLOWLIST(same gotcha lesson as PR #13)Test plan
tests/test_clipboard_url_fetch.py→ 15 passedcodec_triggers.discover_triggers(SkillRegistry)→ 1 trigger found (was 0 on main)git pull && cp skills/clipboard_url_fetch.py ~/.codec/skills/ && pm2 restart codec-observer codec-dashboardhttps://news.ycombinator.com), wait forask_usernotification, confirm, expect notification with fetched contentWhy this trigger first
Considered options —
chrome_openon Slack window-title (low risk, niche use),bitcoin_priceon BTC clipboard (forex/crypto trader use case but narrow), URL →web_fetch(universally useful, bounded privacy via consent gate). Picked URL because it exercises the most parts of the Step 6 plumbing: clipboard matcher + cooldown + require_confirmation gate + delegate-to-existing-skill pattern.🤖 Generated with Claude Code